<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

namespace app\commands;

use Yii;
use Workerman\Worker;
use Workerman\Lib\Timer;
use app\models\Auction;
use app\models\User;
use app\models\Saleorder;
use app\models\BidRcd;
use app\models\BidQueue;
use app\models\BidSericesqueue;
use app\helpers\JPush;
use app\models\Push;
use yii\helpers\ArrayHelper;
use yii\db\Expression;
use yii\console\Controller;
/**
 * This command echoes the first argument that you have entered.
 *
 * This command is provided as an example for you to learn how to create console commands.
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @since 2.0
 */


class WorkermanController extends Controller
{
    /**
     * @var Worker
     */
    private static $_worker;

    /**
     * This command echoes what you have entered as the message.
     * @param string $message the message to be echoed.
     */
    public function actionIndex()
    {
        //创建一个worker实例
        global $worker;
        $worker = new Worker("websocket://" . Yii::$app->params['socketUrl']);
        $worker->name = 'talk';
        //初始化worker
        $worker->onWorkerStart = array($this, 'onWorkerStart');

        Worker::runAll();
    }

    /**
     * workerman初始化函数
     * @param $worker
     */
    public static function onWorkerStart($worker)
    {
        self::$_worker = $worker;
        Timer::add(2, array(__CLASS__, 'setAct'));
        Timer::add(2, array(__CLASS__, 'setRobot'));
        Timer::add(5, array(__CLASS__, 'setSerices'));
        Timer::add(10, array(__CLASS__, 'setRea'));
        Timer::add(20, array(__CLASS__, 'setPush'));
        $worker->onConnect = array(__CLASS__, 'onConnect');
        $worker->onMessage = array(__CLASS__, 'onMessage');
        $worker->onClose = array(__CLASS__, 'onClose');
    }

    /**
     * worker连接回调函数.
     *
     */
    public static function onConnect($worker)
    {
        //echo "someone log in";
    }

    /**
     * worker消息回调函数
     *
     */
    public static function onMessage($connection, $message)
    {

    }

    /**
     * worker连接断开函数
     *
     */
    public static function onClose($connection)
    {
        //echo "some log out";
    }

    /**
     * 推送消息
     */
    public static function setPush()
    {
        /** @var  $push Push */
        $push = Push::find()->where(['state' => Push::STATE_NOT_READ, 'is_send' => Push::SEND_NOT])->one();
        if ($push) {
            $contentid = $push->contentid;
            $user_ids = ArrayHelper::getColumn(Push::find()->where(['state' => Push::STATE_NOT_READ, 'is_send' => Push::SEND_NOT, 'contentid' => $contentid])->all(), function ($element) {
                return JPush::$prefix . $element['user_id'];
            });
            $ret = JPush::pushAccountList($push->title, $push->content, $user_ids,$push->type);
            if ($ret) {
                Push::updateAll(['is_send' => PUSH::SEND_IS], ['contentid' => $contentid]);
            }
        }
    }

    /**
     * 准备开始倒计时
     */
    public static function setRea()
    {
        Auction::updateAll([
            'reacount' => new Expression('case when reacount > 10 then reacount-10 when reacount <=10 then 0 end'),
            'state' => new Expression('case when reacount > 0 then state when reacount = 0 then ' . Auction::STATE_IS_AUCTION . ' end'),
            'updated_at' => new Expression('unix_timestamp(now()) '),
        ], ['state' => Auction::STATE_READY]);
    }

    /**
     * 设置连续拍
     */
    public static function setSerices()
    {
        /** @var  $sericesqueues BidSericesqueue[] */
        $sericesqueues = BidSericesqueue::find()->all();
        foreach ($sericesqueues as $sericesqueue) {

            $topRcd = BidRcd::find()->where(['auction_id' => $sericesqueue->auction_id])->orderBy(['bidrcdid' => SORT_DESC])->one();
            $canCreate = false;
            if (!$topRcd) {
                $canCreate = true;
            } else {
                if ($topRcd->user_id != $sericesqueue->user_id) {
                    /** @var  $topQueue BidQueue */
                    $topQueue = BidQueue::find()->where(['auction_id' => $sericesqueue->auction_id])->orderBy(['bidqueueid' => SORT_DESC])->one();
                    if (!$topQueue || $topQueue->user_id != $sericesqueue->user_id)
                        $canCreate = true;
                }
            }
            if ($canCreate) {//用户不相同才连续拍
                BidQueue::createFromSerice($sericesqueue);
                $sericesqueue->num--;
                if ($sericesqueue->num <= 0) {
                    $sericesqueue->delete();
                } else {
                    $sericesqueue->save(false);
                }
            }
        }
    }

    /**
     * 设置机器人
     */
    public static function setRobot()
    {
        //所有需要机器人的记录
        $auctions = Auction::find()->where(['and', ['state' => Auction::STATE_IS_AUCTION], ['<', 'actcount', 3]])->all();
        /** @var  $users User[] */
        $users = User::find()->indexBy('userid')->where(['type' => User::IS_ROBOT])->all();
        /** @var  $bidrcds BidRcd[] */
        $user_ids = array_keys($users);
        /** @var  $auctions Auction[] */
        foreach ($auctions as $auction) {
            $canCreate = false;
            $count = intval(BidQueue::find()->where(['auction_id' => $auction->auctionid])->count());
            $price = $auction->price + ($auction->scope * $count);
            $all_user_ids = $user_ids;
            if ($price < $auction->default_price) {//小于默认成交价，则继续拍
                $canCreate = true;
            }else if($auction->can_robot == Auction::CAN_ROBOT){//机器人拍中，则不让人拍中
                $topQueue = BidQueue::find()->where(['auction_id' => $auction->auctionid])->orderBy(['bidqueueid' => SORT_DESC])->one();
                $que_user_id = $topQueue ? $topQueue->user_id : 0;
                $change_ids = [$que_user_id];
                if (!in_array($que_user_id, $user_ids)){//出价记录
                    /** @var  $topRcd BidRcd */
                    $topRcd = BidRcd::find()->where(['auction_id' => $auction->auctionid])->orderBy(['bidrcdid' => SORT_DESC])->one();
                    $user_id = $topRcd ? $topRcd->user_id : 0;
                    $change_ids[] = $user_id;
                    if(!in_array($user_id,$user_ids)){//出价队列不存在
                        $canCreate = true;
                    }
                }
                //避免一个人重复拍两次
                $all_user_ids = array_diff($all_user_ids,$change_ids);
            }
            //如果倒计时小于3并且系统默认机器人拍中，或者成交价小于默认成交价
            if ($canCreate) {//机器人拍中
                $user = $users[$user_ids[array_rand($all_user_ids)]];
                $order = Saleorder::getOrCreate($auction, $user);
                $order->num++;
                $order->save(false);
                BidQueue::create($auction, $user);
            }
        }
    }

    /**
     * 竞拍倒计时
     */
    public static function setAct()
    {
        $auctions = Auction::find()->where(['state'=>Auction::STATE_IS_AUCTION])->all();
        /** @var  $auctions Auction[]*/
        foreach($auctions as $auction)
        {
            $actcount = $auction->actcount;
            $price = $auction->price;
            $scope = $auction->scope;
            /** @var  $bidqueues BidQueue*/
            $bidqueues = BidQueue::find()
                ->where(['auction_id'=>$auction->auctionid])
                ->orderBy(['created_at'=>SORT_ASC])
                ->all();
            if(empty($bidqueues)){//无人出价
                $actcount = $actcount > 2 ? $actcount - 2 : 0;//继续倒计时
            }else{
                $endRcd = null;
                foreach($bidqueues as $bidqueue)
                {
                    $price+=$scope;
                    $endRcd = BidRcd::create($bidqueue,$price);
                }
                if($endRcd)
                    BidRcd::updateAll(['state'=>BidRcd::STATE_OUT],['and',['auction_id'=>$auction->auctionid],['<','bidrcdid',$endRcd->bidrcdid]]);
                $actcount = $auction->product->actcount;//重置倒计时
            }
            //不论任何原因，倒计时结束
            if($actcount == 0){
                $auction->end();
            }else{
                $auction->actcount = $actcount;
                $auction->price = $price;
                $auction->save(false);
            }
        }
    }

}
